package com.multiplay.tetris;

import java.util.Random;

public class PlayField
{
	private boolean [][] cup_model = null;
	private GameBlock current_block = null;

	private int current_level;
	private int removed_lines;
	private int score;
    
    public static final int CUP_WIDTH = 10;
    public static final int CUP_HEIGHT = 18;
    
    private static final int MAX_ELEMENTS = 7;
    
    private Random random = null;
    
    public PlayField()
    {
    	random = new Random();
        random.setSeed(System.currentTimeMillis());
    	
        current_level = 1;
        removed_lines = 0;
        score = 0;
        
    	init_model();
    }
    
    private void init_model()
    {
        cup_model = new boolean[CUP_WIDTH][CUP_HEIGHT];

        for (int i = 0; i < CUP_WIDTH; i++)
            for (int j = 0; j < CUP_HEIGHT; j++)
                cup_model[i][j] = false;
    }
    
    public boolean get_model_state(int x, int y)
    {
    	return cup_model[x][y];
    }
    
    public int[] get_block_array()
    {
    	if (current_block == null)
    		return null;
    	
    	return current_block.get_block_coord();
    	
    }
    
    public int get_current_level()
    {
    	return current_level;
    }
    
    public int get_score()
    {
    	return score;
    }
    
    public int get_removed_lines()
    {
    	return removed_lines;
    }
    
    public void move_down(int deep)
    {
    	current_block.move_down(deep);
    }
    
    public boolean rotate_block()
    {
    	return current_block.rotate(this);
    }
    
    public boolean drop_block()
    {
    	int x, y, deep, min_deep = CUP_HEIGHT;;
        
        for (int i = 0; i < 4; i++)
        {
            x = current_block.get_block_coord()[i * 2];
            y = current_block.get_block_coord()[i * 2 + 1];
            deep = 0;
            for (int j = y + 1; j < CUP_HEIGHT; j++)
            {
                if (!cup_model[x][j])
                    deep++;
                else
                    break;
            }
            if (deep < min_deep)
                min_deep = deep;
        }
        
        if (min_deep == 0)
        	return false;;
        
        current_block.move_down(min_deep);
        
        return true;
    }
    
    public boolean step_left()
    {
    	int x, y;
        boolean move = true;
        
        for (int i = 0; i < 4; i++)
        {
            x = current_block.get_block_coord()[i * 2];
            y = current_block.get_block_coord()[i * 2 + 1];
            
            if (x == 0 || cup_model[x - 1][y])
            {
                move = false;
                break;
            }
        }
        if (move)
            current_block.step_left();
        
        return move;
    }

    public boolean step_right()
    {
    	int x, y;
        boolean move = true;
        
        for (int i = 0; i < 4; i++)
        {
            x = current_block.get_block_coord()[i * 2];
            y = current_block.get_block_coord()[i * 2 + 1];
            
            if (x + 1 == CUP_WIDTH || cup_model[x + 1][y])
            {
                move = false;
                break;
            }
        }
        if (move)
            current_block.step_rigth();
        
        return move;
    }
    
    public boolean timer_event()
    {
    	boolean game_over = false;
    	
    	if (current_block == null ||
    		check_tauch(current_block.get_block_coord()))
    	{
    		current_block =
    			GameBlock.create_block(random.nextInt(MAX_ELEMENTS));
    		if (!first_check(current_block.get_block_coord(), true))
    			game_over = true;;
    	}
    	else
    	{
    		move_down(1);
    	}
    	
    	int removed_lines = remove_full_lines();
    	if (removed_lines > 0)
    		calc_score(removed_lines);
    	
    	return game_over;
    }
    
    public boolean first_check(int [] block_coord, boolean set)
    {
        boolean rc = true;
        int x, y;
        
        for (int i = 0; i < 4; i++)
        {
            x = block_coord[i * 2];
            y = block_coord[i * 2 + 1];
            
            if (cup_model[x][y])
            {
                rc = false;
                break;
            }
        }
        
        if (!rc && set)
            set_block_to_model(block_coord);
        
        return rc;
    }
    
    private void calc_score(int removed_lines)
    {
    	score += removed_lines * removed_lines;
    }
    
    private void set_block_to_model(int [] block_coord)
    {
        int x, y;
        
        for (int i = 0; i < 4; i++)
        {
            x = block_coord[i * 2];
            y = block_coord[i * 2 + 1];
            
            cup_model[x][y] = true;
        }
        
        current_block = null;
    }
    
    private boolean check_tauch(int [] block_coord)
    {
        boolean rc = false;
        int x, y;

        for (int i = 0; i < 4; i++)
        {
            x = block_coord[i * 2];
            y = block_coord[i * 2 + 1];
            
            if (y + 1 == CUP_HEIGHT)
            {
                rc = true;
                break;
            }
            if (cup_model[x][y + 1])
            {
                rc = true;
                break;
            }
        }

        if (rc)
            set_block_to_model(block_coord);
        
        return rc;
    }
    
    private void remove_line(int line)
    {
    	removed_lines++;
    	
        if (line == 0)
        {
            for (int i = 0; i < CUP_WIDTH; i++)
                cup_model[i][0] = false;
            
            return;
        }
        int filled = 0;
        for (int y = line; y > 0; y--)
        {
            filled = 0;
            for (int x = 0; x < CUP_WIDTH; x++)
            {
                cup_model[x][y] = cup_model[x][y - 1];
                if (cup_model[x][y - 1])
                    filled++;
            }
            if (filled == 0)
                break;
        }
        if (filled != 0)
            for (int i = 0; i < CUP_WIDTH; i++)
                cup_model[i][0] = false;
    }
    
    private int remove_full_lines()
    {
        int full = 0;
        int removed = 0;
        
        for (int y = CUP_HEIGHT - 1; y >= 0; y--)
        {
            full = 0;
            for (int x = 0; x < CUP_WIDTH; x++)
            {
                if (cup_model[x][y])
                    full++;
            }
            if (full == CUP_WIDTH)
            {
            	removed++;
                remove_line(y);
                removed += remove_full_lines();
                break;
            }
        }
        return removed;
    }
}
